const fs = require('fs-extra');
const path = require('path');
const URL = require('url');
const wkhtmltopdf = require('wkhtmltopdf');
const utility = require('../../../utility');
const Html = require('./html');

class Pdf {
  constructor({
    template,
    staticDir,
    staticDirName,
    coverTemplate,
    workDir,
    headerLeft,
    headerRight,
    footerCenter,
  }) {
    this.template = template;
    this.staticDir = staticDir;
    if (this.staticDir) {
      this.staticDirName = staticDirName || path.basename(this.staticDir);
    }
    this.coverTemplate = coverTemplate;
    this.commonStaticDir = path.join(__dirname, '..', 'static');

    this.prepared = false;
    this.workDir = workDir;
    this.headerLeft = headerLeft;
    this.headerRight = headerRight;
    this.footerCenter = footerCenter;

    this.generating = false;
  }

  async preGenerate() {
    if (this.prepared) {
      return;
    }
    await fs.ensureDir(this.workDir);
    // copy common static files to temp dir
    await fs.copy(this.commonStaticDir, path.join(this.workDir, path.basename(this.commonStaticDir)));
    // override customize static files to temp dir
    if (this.staticDir && fs.existsSync(this.staticDir)) {
      await fs.copy(this.staticDir, path.join(this.workDir, this.staticDirName));
    }
    this.prepared = true;
  }

  async generate(data, outputPath, attaches = []) {
    if (this.generating) {
      throw new Error('Prohibit generating multi file');
    }
    this.generating = true;
    await this.preGenerate();
    // generate html files to temp dir
    await new Html({ template: this.template }).generate(data, path.join(this.workDir, 'index.html'));
    if (this.coverTemplate) {
      await new Html({ template: this.coverTemplate }).generate(data, path.join(this.workDir, 'cover.html'));
    }
    // copy attached files to temp dir
    await Promise.all(attaches.map((a) => fs.copy(a, path.join(this.workDir, path.basename(a)))));

    // convert html to pdf
    const absPath = utility.absPath(path.join(this.workDir, 'index.html'));
    const dir = path.dirname(absPath);
    const opts = {};
    if (this.headerRight) {
      opts.headerLeft = this.headerLeft;
      opts.headerRight = this.headerRight;
      opts.headerLine = true;
      opts.headerFontSize = 10;
    }
    if (this.footerCenter) {
      opts.footerCenter = this.footerCenter;
      opts.footerRight = '[page]';
      opts.footerLine = true;
      opts.footerFontSize = 10;
    }
    if (this.coverTemplate) {
      opts.cover = utility.absPath(path.join(this.workDir, 'cover.html'));
    }
    // replace path of wkhtmltopdf.exe on window
    if (process.platform === 'win32') {
      wkhtmltopdf.command = path.join(process.cwd(), 'phoenix', 'bin', 'wkhtmltopdf.exe');
    }
    const rs = wkhtmltopdf(URL.pathToFileURL(absPath).href, {
      ...opts,
      allow: dir,
      pageSize: 'a4',
      marginTop: '20mm',
      marginBottom: '20mm',
    });
    await new Promise((res, rej) => {
      rs.pipe(fs.createWriteStream(outputPath))
        .once('close', res)
        .once('error', rej);
    });
    this.generating = false;
  }

  async clear() {
    await fs.remove(this.workDir);
    this.prepared = false;
  }
}

module.exports = Pdf;
